﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;

namespace HB.Expand
{
    public static class Object2Object
    {
        /// <summary>
        /// 将class中{byte,sbyte,bool,short ,ushort,uint,int,long,ulong,float,double} and list of them依次转入字节流
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="isLittleEndian"></param>
        /// <returns></returns>
        public static byte[] MapToStream<T>(this T t, bool isLittleEndian = true) where T : class
        {
            bool isPaltFormLettleEnding = 0.IsLettleEndingPlatfrom();
            bool isNeedReserve = isPaltFormLettleEnding != isLittleEndian;
            Dictionary<Type, Func<T, object, byte[]>> dicmap = new Dictionary<Type, Func<T, object, byte[]>>()
            {
                {typeof (sbyte ), (tt,p)=>{var data= (sbyte )p ;byte target=0; if(data>=0){target=(byte)data; }else {target=(byte)(data +256); } return new byte[1]{ target }; } },
                {typeof (bool  ), (tt,p)=>{return   ((bool )p)?new byte[1]{ 1}:new byte[1]{ 0}; } },
                {typeof (byte  ), (tt,p)=>{return   new byte[1]{ (byte)p }; }  },
                {typeof (short  ),(tt,p)=>{return  BitConverter.GetBytes (  (short)p) ;  } },
                {typeof (ushort), (tt,p)=>{return  BitConverter.GetBytes (  (ushort)p) ; } },
                {typeof (int  ),  (tt,p)=>{return  BitConverter.GetBytes (  (int)p) ;    } },
                {typeof (uint ),  (tt,p)=>{return  BitConverter.GetBytes (  (uint)p) ;   } },
                {typeof (long ),  (tt,p)=>{return  BitConverter.GetBytes (  (long)p) ;   } },
                {typeof (ulong ), (tt,p)=>{return  BitConverter.GetBytes (  (ulong)p) ;  } },
                {typeof (float ), (tt,p)=>{return  BitConverter.GetBytes (  (float)p) ;  } },
                {typeof (double ),(tt,p)=>{return  BitConverter.GetBytes (  (double)p) ; } },
            };
            byte[] DoForResult<T>(object o)
            {
                T[] lsobject = (T[])o;
                List<byte> lsresult = new List<byte>();
                foreach (var oitem in lsobject)
                {
                    lsresult.AddRange(dicmap[typeof(T)](null, oitem));
                }
                return lsresult.ToArray();
            }
            dicmap.Add(typeof(sbyte[]), (tt, p) => { return DoForResult<sbyte>(p); });
            dicmap.Add(typeof(bool[]), (tt, p) => { return DoForResult<bool>(p); });
            dicmap.Add(typeof(byte[]), (tt, p) => { return DoForResult<byte>(p); });
            dicmap.Add(typeof(short[]), (tt, p) => { return DoForResult<short>(p); });
            dicmap.Add(typeof(ushort[]), (tt, p) => { return DoForResult<ushort>(p); });
            dicmap.Add(typeof(int[]), (tt, p) => { return DoForResult<int>(p); });
            dicmap.Add(typeof(uint[]), (tt, p) => { return DoForResult<uint>(p); });
            dicmap.Add(typeof(long[]), (tt, p) => { return DoForResult<long>(p); });
            dicmap.Add(typeof(ulong[]), (tt, p) => { return DoForResult<ulong>(p); });
            dicmap.Add(typeof(float[]), (tt, p) => { return DoForResult<float>(p); });
            dicmap.Add(typeof(double[]), (tt, p) => { return DoForResult<double>(p); });
            List<byte> ls = new List<byte>();
            foreach (var p in typeof(T).GetProperties())
            {
                if (dicmap.ContainsKey(p.PropertyType))
                {
                    var value = p.GetValue(t, null);
                    var data = dicmap[p.PropertyType](t, value);
                    if (isNeedReserve)
                    {
                        Array.Reverse(data);
                    }
                    ls.AddRange(data);
                }
            }
            return ls.ToArray();
        }
        /// <summary>
        /// 将结构体转为字节流
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static byte[] MapToBytes<T>(this T obj) where T : struct
        {
            int size = Marshal.SizeOf(obj);
            byte[] bytes = new byte[size];
            IntPtr structPtr = Marshal.AllocHGlobal(size);
            Marshal.StructureToPtr(obj, structPtr, false);
            Marshal.Copy(structPtr, bytes, 0, size);
            Marshal.FreeHGlobal(structPtr);
            return bytes;
        }
    }
}
